package com.example.permissionservice.service;

import com.example.permissionservice.dao.UserWithRoleMapper;
import com.myprojects.common.pojo.UserWithRole;
import com.myprojects.common.pojo.UserWithRoleExample;

import com.myprojects.common.dto.Msg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserWithRoleService {

    /**
     * 密码编码器
     */
    public final static BCryptPasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();

    @Autowired
    UserWithRoleMapper mapper;

    @Autowired
    UserTokenService userTokenService;

    public long countByExample(UserWithRoleExample example) {
        return mapper.countByExample(example);
    }

    public int deleteLotsByPrimaryKey(List<Integer> idList) {
        userTokenService.deleteUserById(idList.toArray(new Integer[]{}));
        return mapper.deleteLotsByPrimaryKey(idList);
    }

    public int insertSelective(UserWithRole record){
        record.setEncrypt_password(PASSWORD_ENCODER.encode(record.getPassword()));//插入密码前必须先加密密码
        return mapper.insertSelective(record);
    }

    public List<UserWithRole> selectAllUser(){
        return mapper.selectByExample(null);
    }

    public UserWithRole selectByPrimaryKey(Integer id){
        return mapper.selectByPrimaryKey(id);
    }

    public List<UserWithRole> selectByExample(UserWithRoleExample example){
        return mapper.selectByExample(example);
    }

    public UserWithRole selectByUsername(String username){
        return mapper.selectByUsername(username);
    }

    public int updateByPrimaryKeySelective(UserWithRole record){
        String password = record.getPassword();
        if (password != null && !"".equals(password))
            record.setEncrypt_password(PASSWORD_ENCODER.encode(password));//插入密码前必须先加密密码
        int iResult = mapper.updateByPrimaryKeySelective(record);
        userTokenService.updateTokenUser(record);
        return iResult;
    }

    /**
     * 该方法会通过用户名检查该用户是否存在
     * @return 该用户是否存在的Boolean
     */
    public Boolean checkUsername(String username ){
        long iResult = 0;
        UserWithRoleExample example = new UserWithRoleExample();
        example.createCriteria().andUsernameLike(username);
        try{
            iResult = mapper.countByExample(example);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Boolean bResult = iResult >= 1;//大于1则说明该用户名存在

        return bResult;
    }

    /**
     * 该方法会检查用户名是否存在
     * @return 返回一个Boolean值，true表示用户名存在，<br>
     * false表示用户名不存在
     */
    public Boolean isNewUsernameExist(String newUsername, Integer oldId){
        long iResult = 0;
        Boolean bResult = null;
        newUsername = (newUsername == null ? "" : newUsername);

        UserWithRoleExample example = new UserWithRoleExample();
        example.createCriteria().andUsernameLike(newUsername);
        UserWithRole oldUser = null;

        try{
            iResult = mapper.countByExample(example);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try{
            oldUser = mapper.selectByPrimaryKey(oldId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //如果用户名重复
        if (iResult > 0){
            //如果该用户存在，且用户名重复，且新用户名跟旧用户名一致，就仍可以修改
            if (oldUser!=null && newUsername.equals(oldUser.getUsername())){
                bResult = false;
            }else {//如果用户名重复，且新用户名跟旧用户名不一致，则提示用户名重复
                bResult = true;
            }
        }else {
            bResult = false;
        }

        return bResult;
    }

    /**
     * 该方法会检查用户的所有属性是否合法，给新增用户使用
     * @return 携带错误信息的map，若map.size()>0则说明验证失败
     */
    public Map<String,Object> checkNewUser(UserWithRole user, BindingResult bindingResult){
        Map<String , Object> errorMap = new HashMap<>();

        //先检查数据格式是否有误
        if (bindingResult.hasErrors()){
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            for (FieldError error : fieldErrors){
                errorMap.put(error.getField(),error.getDefaultMessage());
            }
        }
        //再检查用户名是否重复
        if (isNewUsernameExist(user.getUsername(),user.getId())){
            errorMap.put("username","该用户名已存在!");
        }
        //移除没有必要的错误
        errorMap.remove("password2");
        //返回errorMap
        return  errorMap;
    }

    /**
     * 该方法会检查用户的所有属性是否合法，给修改用户使用
     * @return 携带错误信息的map，若map.size()>0则说明验证失败
     */
    public Map<String,Object> checkUpdateUser(UserWithRole user, BindingResult bindingResult){
        Map<String , Object> errorMap = new HashMap<>();

        //先检查数据格式是否有误
        if (bindingResult.hasErrors()){
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            for (FieldError error : fieldErrors){
                errorMap.put(error.getField(),error.getDefaultMessage());
            }
        }
        //再检查密码是否通过验证(为空反而能更新，否则不符合规范的密码不能更新)
        if (user.getPassword() == null || "".equals(user.getPassword())){
            errorMap.remove("password");
        }
        //再检查用户名是否重复
        if (isNewUsernameExist(user.getUsername(),user.getId())){
            errorMap.put("username","该用户名已存在!");
        }
        //移除没有必要的错误
        errorMap.remove("password2");
        //返回errorMap
        return  errorMap;
    }

    /**
     * 该方法用于检查修改的密码的是否有问题
     * @return 携带错误信息的map，若map.size()>0则说明验证失败
     */
    @ResponseBody
    public Map<String,Object> checkUpdatePassword(UserWithRole user, BindingResult bindingResult){
//        Msg result = new Msg();//尝试修改密码后的返回结果
        Map<String , Object> errorMap = new HashMap<>();

        //先检查用户信息有没有错误
        //先检查数据格式是否有误
        if (bindingResult.hasErrors()){
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            for (FieldError error : fieldErrors){
                errorMap.put(error.getField(),error.getDefaultMessage());
            }
        }
        if ("二次密码不能为空!".equals(errorMap.get("password2"))){
            errorMap.put("password2","新密码不能为空!");
        }
        //移除没有必要的错误
        errorMap.remove("username");
        errorMap.remove("nickname");
        errorMap.remove("email");

        return errorMap;
    }

    /**
     * 该方法用于验证未加密密码与加密后的密码是否一致
     * @param rawPassword 为未加密的原密码
     * @param encodedPassword 为加密后的数据库密码
     * @return 返回一个Boolean值，true为一致，false为不一致
     */
    public Boolean matchPassword(String rawPassword,String encodedPassword){
        return PASSWORD_ENCODER.matches(rawPassword,encodedPassword);
    }

    /**
     * 该方法用于修改密码，会返回一个带修改失败原因的Msg对象
     */
    public Msg updatePassword(String accessToken, UserWithRole inputUser, BindingResult bindingResult){
        Msg result = new Msg();//尝试修改密码后的返回结果
        Boolean bUpdate = false;//是否修改成功的标识

        if (accessToken == null ||  "".equals(accessToken) || "null".equals(accessToken)){
            result.setMsg("用户token不能为空！");
            result.setCode(400);
            return result;
        }

        //先调用检查接口检查输入的用户信息有没有错误
        Map errorMap = checkUpdatePassword(inputUser, bindingResult);

        //如果原密码和修改密码都不为空，则尝试修改
        if (errorMap.size() <= 0){
            try{
                UserWithRole redisUser = null;
                HashMap<String, UserWithRole> redisUserMap = userTokenService.searchUserByString(accessToken+"*");
                for (UserWithRole user : redisUserMap.values()){
                    redisUser = user;
                    break;
                }
                inputUser.setId(redisUser.getId());
                UserWithRole dbUser = selectByPrimaryKey(inputUser.getId());
                //如果跟数据库里的密码正确
//                System.out.println("inputUser.getPassword():"+inputUser.getPassword());
//                System.out.println("inputUser.getPassword2():"+inputUser.getPassword2());
//                System.out.println("dbUser.getEncrypt_password():"+dbUser.getEncrypt_password());
//                System.out.println("match:"+matchPassword(inputUser.getPassword(),dbUser.getEncrypt_password()));
                if (matchPassword(inputUser.getPassword(),dbUser.getEncrypt_password())){
                    inputUser.setPassword(inputUser.getPassword2());//把要修改的密码改为新密码
                    int iUpdate = updateByPrimaryKeySelective(inputUser);
                    if (iUpdate > 0){//大于0为成功
                        result.setMsg("密码修改成功！");
                        result.setCode(200);
                    }else {
                        result.setMsg("密码修改失败！");
                        result.setCode(400);
                    }
                }else {//否则则是密码错误
                    result.setMsg("原密码错误！修改失败");
                    result.setCode(400);
                }
            }catch (Exception e){
                e.printStackTrace();
                result.setMsg("密码修改失败！");
                result.setCode(400);
            }
        }else {//否则直接使用检查后的结果
            result.addData("errorMap",errorMap);
            result.setMsg("数据格式有误！");
            result.setCode(400);
        }

        return result;
    }
}
